/**
 * 
 */
package it.uniroma3.dia.digraph.algorithm.utility;

import java.awt.Point;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;

import org.graphdrawing.graphml.xmlns.NodeType;

/**
 * @author BarycentricCoords
 *
 */
class Segment {	
	/**
	 * * The algorithm is described in "Introduction to algorithms" 3 ed. pag 1018.
	 * @param a
	 * @param b
	 * @return
	 */
	public static double crossProduct(Point a, Point b){
		return Utility.det(a.getX(),b.getX(),a.getY(),b.getY());
		
	}
	
	
	/**
	 * The algorithm is described in "Introduction to algorithms" 3 ed. pag 1018.
	 * @param a
	 * @param b
	 * @param c
	 * @return
	 */
	public static double direction(Point a, Point b, Point c){		
		return crossProduct(useFirstAsOrigin(a, c), useFirstAsOrigin(b, a));
	}
	
	public static boolean existsIntersection(Point a, Point b, Point c, Point d ){
		double d1,d2,d3,d4;
		d1 = direction(c, d, a);
		d2 = direction(c, d, b);
		d3 = direction(a, b, c);
		d4 = direction(a, b, d);
		if ( ((d1>0 && d2<0) || (d1<0 && d2>0)) &&
			 ((d3>0 && d4<0) || (d3<0 && d4>0))    )
			return true;
		if (d1==0 && onSameSegment(c, d, a))
			return true;
		if (d2==0 && onSameSegment(c, d, b))
			return true;
		if(d3==0 && onSameSegment(a, b, c))
			return true;
		if (d4==0 && onSameSegment(a, b, d))
			return true;
		return false;
	}
	
	/**
	 * Returns the point r, with A,B and the distance of the new point from B
	 * 		
	 *	A...B....r
	 *	A=source, B=target, r=new point, Br=distFromTarget
	 * @param sourceX
	 * @param sourceY
	 * @param targetX
	 * @param targetY
	 * @param distFromTarget
	 * 
	 * @return
	 */
	public static Point getPointOnProlung(double xs, double ys, double xt,
			double yt, double distFromTarget) {
		Point result = new Point();
		
		double ST, xp, yp, deltaXts, deltaYts, deltaXpt, deltaYpt;

		// ST : TP = deltaXst : deltaXtp
		// ST : TP = deltaYst : deltaYtp
		deltaXts = xt - xs;
		deltaYts = yt - ys;
		
		//calc. ST
		xs -= xt;
		ys -= yt;
		ST = Math.sqrt(xs*xs + ys*ys);
		
		deltaXpt = (distFromTarget * deltaXts)/ST;
		deltaYpt = (distFromTarget * deltaYts)/ST;
		
		xp = xt + deltaXpt; 
		yp = yt + deltaYpt; 
				
		
		result.setLocation(xp, yp);
		
		
		return result;
	}
	
	public static boolean intersection(double x1, double y1, double x2, double y2,
			double x3, double y3, double x4, double y4) {
		Line2D.Double l1  = new Line2D.Double(x1, y1, x2, y2);
		Line2D.Double l2  = new Line2D.Double(x3, y3, x4, y4);
//		System.out.println(l1.intersectsLine(l2)+": "+x1+" "+y1+" "+x2+" "+y2+" "+x3+" "+y3+" "+x4+" "+y4); //TODO: LEVAMI
////		new Scanner(System.in).next();
		return l1.intersectsLine(l2);
	}
	
	/**
	 * Checks whether segments AB and CD intersect.
	 * The algorithm is described in "Introduction to algorithms" 3 ed. pag 1018.
	 * @param a an endpoint of the first segment
	 * @param b an endpoint of the first segment
	 * @param c an endpoint of the second segment
	 * @param d an endpoint of the second segment
	 * @return true if the segments intersect, false otherwise
	 */
	public static boolean intersection(Point a, Point b, Point c, Point d){
		return Line2D.linesIntersect(a.getX(), a.getY(), b.getX(), b.getY(), c.getX(), c.getY(), d.getX(), d.getY()); 
	
	}
	
	/**
	 * Calculates the length of segment AB
	 * @param xa
	 * @param ya
	 * @param xb
	 * @param yb
	 * @return
	 */
	public static double length (double xa, double ya, double xb, double yb){
		xa -= xb;
		ya -= yb;
		return Math.sqrt(xa*xa + ya*ya);
	}
	
	/**
	 * Returns the midpoint of the segment ab
	 * @param a the first segment endpoint
	 * @param b the second segment endpoint
	 * @return the midpoint of the segment ab
	 */
	public static Double midPoint(Double a, Double b) {		
		return new Point2D.Double(0.5*a.x+0.5*b.x, 0.5*a.y + 0.5*b.y);
	}


	public static Double midPoint(NodeType a, NodeType b) {
		double x, y;
		x = 0.5 * a.getX() + 0.5 * b.getX();
		y = 0.5 * a.getY() + 0.5 * b.getY();
		return new Point2D.Double(x,y);
	}


	/**
	 * The algorithm is described in "Introduction to algorithms" 3 ed. pag 1018.
	 * @param i
	 * @param j
	 * @param k
	 * @return
	 */
	public static boolean onSameSegment(Point i, Point j, Point k){
		if ((Math.min(i.getX(), j.getX()) <= k.getX() && k.getX() <= Math.max(i.getX(), j.getX())) &&
			(Math.min(i.getY(), j.getY()) <= k.getY() && k.getY() <= Math.max(i.getY(), j.getY())) 	)
			return true;
		return false;
	}


	/**
	 * @param origin
	 * @param p
	 * @return
	 */
	public static Point useFirstAsOrigin(Point origin, Point p){
		Point result = new Point();
		result.setLocation(p.getX() - origin.getX(), p.getY() - origin.getY());
		return result;
	}
}
